
TOOL.Category		= "Constraints"
TOOL.Name			= "#Easy Precision"
TOOL.Command		= nil
TOOL.ConfigName		= ""


TOOL.ClientConVar[ "forcelimit" ]	= "0"
TOOL.ClientConVar[ "freeze" ]	 	= "1"
TOOL.ClientConVar[ "nocollide" ]	= "1"
TOOL.ClientConVar[ "nocollideall" ]	= "0"
TOOL.ClientConVar[ "rotation" ] 	= "15"
TOOL.ClientConVar[ "rotate" ] 		= "1"
TOOL.ClientConVar[ "offset" ]	 	= "0"
TOOL.ClientConVar[ "torquelimit" ] 	= "0"
TOOL.ClientConVar[ "friction" ]	 	= "0"
TOOL.ClientConVar[ "mode" ]	 	= "1"
TOOL.ClientConVar[ "width" ]	 	= "1"
TOOL.ClientConVar[ "offsetpercent" ] 	= "1"
TOOL.ClientConVar[ "removal" ]	 	= "0"
TOOL.ClientConVar[ "move" ]	 	= "1"
TOOL.ClientConVar[ "physdisable" ]	= "0"
TOOL.ClientConVar[ "ShadowDisable" ]	= "0"
TOOL.ClientConVar[ "allowphysgun" ]	= "0"
TOOL.ClientConVar[ "autorotate" ]	= "0"
TOOL.ClientConVar[ "massmode" ]		= "0"
TOOL.ClientConVar[ "nudge" ]		= "25"
TOOL.ClientConVar[ "nudgepercent" ]	= "1"

//adv ballsocket
TOOL.ClientConVar[ "advballsocket" ]	= "0"
TOOL.ClientConVar[ "XRotMin" ]		= "-180"
TOOL.ClientConVar[ "XRotMax" ]		= "180"
TOOL.ClientConVar[ "YRotMin" ]		= "-180"
TOOL.ClientConVar[ "YRotMax" ]		= "180"
TOOL.ClientConVar[ "ZRotMin" ]		= "-180"
TOOL.ClientConVar[ "ZRotMax" ]		= "180"
TOOL.ClientConVar[ "XRotFric" ]		= "0"
TOOL.ClientConVar[ "YRotFric" ]		= "0"
TOOL.ClientConVar[ "ZRotFric" ]		= "0"
TOOL.ClientConVar[ "FreeMov" ]		= "0"


TOOL.ClientConVar[ "enablefeedback" ]	= "1"
TOOL.ClientConVar[ "chatfeedback" ]	= "1"
TOOL.ClientConVar[ "nudgeundo" ]	= "0"


TOOL.inuse = nil
TOOL.axis = 0
TOOL.axisY = 0
TOOL.axisZ = 0
TOOL.realdegrees = 0
TOOL.lastdegrees = 0
TOOL.realdegreesY = 0
TOOL.lastdegreesY = 0
TOOL.realdegreesZ = 0
TOOL.lastdegreesZ = 0
TOOL.OldPos = 0
TOOL.axis2 = 0
TOOL.axisY2 = 0
TOOL.axisZ2 = 0
TOOL.realdegrees2 = 0
TOOL.lastdegrees2 = 0
TOOL.realdegrees2Y = 0
TOOL.lastdegrees2Y = 0
TOOL.realdegrees2Z = 0
TOOL.lastdegrees2Z = 0
TOOL.OldPos2 = 0

function TOOL:DoParent( Ent1, Ent2 )
	local TempEnt = Ent2
	if !(Ent1 && Ent1:IsValid() && Ent1:EntIndex() != 0) then
		self:SendMessage( "Oops, First Target was world or somthing invalid" )
		return
	end
	if !(Ent2 && Ent2:IsValid() && Ent2:EntIndex() != 0) then
		self:SendMessage( "Oops, Second Target was world or somthing invalid" )
		return
	end
	if ( Ent1 == Ent2 ) then
		self:SendMessage( "Oops, Can't parent somthing to itself" )
		return
	end
	Ent1:SetMoveType(MOVETYPE_NONE)
	local disablephysgun = self:GetClientNumber( "allowphysgun" ) == 0
	Ent1.PhysgunDisabled = disablephysgun
	Ent1:SetUnFreezable( disablephysgun )
	local Phys1 = Ent1:GetPhysicsObject()
	if Phys1:IsValid() then
		Phys1:EnableCollisions( false )
	end
	while true do
		if ( !TempEnt:GetParent():IsValid() ) then
			Ent1:SetParent( Ent2 )
			if self:GetClientNumber( "massmode" ) == 0 then self:SendMessage( "Parent Set." ) end
			Phys1:Wake()
			break
		elseif ( TempEnt:GetParent() == Ent1 ) then
			UndoParent( TempEnt )
			timer.Simple( 0.1, Ent1.SetParent, Ent1, Ent2 )  //delay to stop crash
			self:SendMessage( "Oops, Closed Parent Loop Detected; Broken loop and set parent." )
			break
		else
			TempEnt = TempEnt:GetParent()
		end
	end
	Phys1:Wake()
	//Phys1:UpdateShadow(Ent1:GetAngles(),Ent1:GetAngles())
end

function TOOL:UndoParent( Ent1 )
	Ent1:SetParent( nil )
	Ent1:SetMoveType(MOVETYPE_VPHYSICS)
	Ent1.PhysgunDisabled = false
	Ent1:SetUnFreezable( false )
	local Phys1 = Ent1:GetPhysicsObject()
	if Phys1:IsValid() then
		Phys1:EnableCollisions( true )
		Phys1:Wake()
		//Phys1:UpdateShadow(Ent1:GetAngles(),Ent1:GetAngles())
	end
end

function TOOL:DoConstraint()

	// Get information we're about to use
	local Ent1,  Ent2  = self:GetEnt(1),    self:GetEnt(2)

	if ( !Ent1:IsValid() || CLIENT ) then
		self:ClearObjects()
		return false
	end
	// Get client's CVars
	local mode		= self:GetClientNumber( "mode", 1 )
	local forcelimit 	= self:GetClientNumber( "forcelimit", 0 )
	local freeze		= util.tobool( self:GetClientNumber( "freeze", 1 ) )
	local nocollide		= self:GetClientNumber( "nocollide", 0 )
	local nocollideall	= util.tobool( self:GetClientNumber( "nocollideall", 0 ) )
	local torquelimit	= self:GetClientNumber( "torquelimit", 0 )
	local width		= self:GetClientNumber( "width", 1 )
	local friction		= self:GetClientNumber( "friction", 0 )
	local physdis		= util.tobool( self:GetClientNumber( "physdisable", 0 ) )

	local Bone1, Bone2 = self:GetBone(1),   self:GetBone(2)
	local LPos1, LPos2 = self:GetLocalPos(1),self:GetLocalPos(2)
	local Phys1 = self:GetPhys(1)

	if ( self:GetClientNumber( "massmode" ) == 1 ) then
		local NumApp = 0
		local TargetEnts = {}
		local EntsTab = {}
		local ConstsTab = {}
		GetAllEnts(Ent1, TargetEnts, EntsTab, ConstsTab)
		for key,CurrentEnt in pairs(TargetEnts) do
			if ( CurrentEnt and CurrentEnt:IsValid() ) then
				if !(CurrentEnt == Ent2 ) then
					local CurrentPhys = CurrentEnt:GetPhysicsObject()
					if ( CurrentPhys:IsValid() ) then
						/*if autorotate then
							local angle = CurrentPhys:RotateAroundAxis( Vector( 0, 0, 1 ), 0 )
							angle.p = (math.Round(angle.p/45))*45
							angle.r = (math.Round(angle.r/45))*45
							angle.y = (math.Round(angle.y/45))*45
							CurrentPhys:SetAngle( angle )
							CurrentPhys:Wake()
						end*/
						CurrentPhys:EnableCollisions( !nocollideall )
						CurrentPhys:EnableMotion( !freeze )
						if ( CurrentEnt:GetPhysicsObjectCount() < 2 ) then //not a ragdoll
							if ( mode == 3 ) then //weld
								local constraint = constraint.Weld( CurrentEnt, Ent2, 0, Bone2, forcelimit,  util.tobool( nocollide ) )
								if (constraint) then
									undo.Create("Precision Weld")
									undo.AddEntity( constraint )
									undo.SetPlayer( self:GetOwner() )
									undo.Finish()
									self:GetOwner():AddCleanup( "constraints", constraint )
								end
							elseif ( mode == 2 ) then //doaxis
								local constraint = constraint.Axis( CurrentEnt, Ent2, 0, Bone2, LPos1, LPos2, forcelimit, torquelimit, friction, nocollide )
								if (constraint) then
									undo.Create("Precision Axis")
									undo.AddEntity( constraint )
									undo.SetPlayer( self:GetOwner() )
									undo.Finish()
									self:GetOwner():AddCleanup( "constraints", constraint )
								end
							elseif ( mode == 4 ) then //ballsocket or advballsocket
								if ( self:GetClientNumber( "advballsocket", 0 ) == 1 ) then
									local constraint = constraint.AdvBallsocket( CurrentEnt, Ent2, 0, Bone2, LPos1, LPos2, forcelimit, torquelimit, self:GetClientNumber( "XRotMin", -180 ), self:GetClientNumber( "YRotMin", -180 ), self:GetClientNumber( "ZRotMin", -180 ), self:GetClientNumber( "XRotMax", 180 ), self:GetClientNumber( "YRotMax", 180 ), self:GetClientNumber( "ZRotMax", 180 ), self:GetClientNumber( "XRotFric", 0 ), self:GetClientNumber( "YRotFric", 0 ), self:GetClientNumber( "ZRotFric", 0 ), self:GetClientNumber( "FreeMov", 0 ), nocollide )
									if (constraint) then
										undo.Create("Precision Advanced Ballsocket")
										undo.AddEntity( constraint )
										undo.SetPlayer( self:GetOwner() )
										undo.Finish()
										self:GetOwner():AddCleanup( "constraints", constraint )
									end
								else
									local constraint = constraint.Ballsocket( CurrentEnt, Ent2, 0, Bone2, LPos2, forcelimit, torquelimit, nocollide )
									if (constraint) then
										undo.Create("Precision Ballsocket")
										undo.AddEntity( constraint )
										undo.SetPlayer( self:GetOwner() )
										undo.Finish()
										self:GetOwner():AddCleanup( "constraints", constraint )
									end
								end
							elseif ( mode == 5 ) then //slider
								local constraint = constraint.Slider( CurrentEnt, Ent2, 0, Bone2, LPos1, LPos2, width )
								if (constraint) then
									undo.Create("Precision Slider")
									undo.AddEntity( constraint )
									undo.SetPlayer( self:GetOwner() )
									undo.Finish()
									self:GetOwner():AddCleanup( "constraints", constraint )
								end
							end
							if (  util.tobool( nocollide ) && iNum != 0) then // not weld/axis/ballsocket or single application
								local constraint = constraint.NoCollide(CurrentEnt, Ent2, 0, Bone2)
							end
						end
						if ( mode == 6 ) then //parent
							self:DoParent( CurrentEnt, Ent2 )
						end
					end
					CurrentEnt:DrawShadow( !shadowdisable )
					if physdis then
						CurrentEnt:SetMoveType(MOVETYPE_NONE)
						CurrentEnt.PhysgunDisabled = disablephysgun
						CurrentEnt:SetUnFreezable( disablephysgun )
					elseif !( mode == 6 ) then
						CurrentEnt:SetMoveType(MOVETYPE_VPHYSICS)
						CurrentEnt.PhysgunDisabled = false
						CurrentEnt:SetUnFreezable( false )
					end
				end
			end
			NumApp = NumApp + 1
		end
		self:SendMessage( NumApp .. " props constrained." )
	else
		if ( mode == 3 ) then //weld
			local constraint = constraint.Weld( Ent1, Ent2, Bone1, Bone2, forcelimit,  util.tobool( nocollide ) )
			if (constraint) then
				self:SendMessage( "Prop welded." )
				undo.Create("Precision Weld")
				undo.AddEntity( constraint )
				undo.SetPlayer( self:GetOwner() )
				undo.Finish()
				self:GetOwner():AddCleanup( "constraints", constraint )
			end
		elseif ( mode == 2 ) then //doaxis
			local constraint = constraint.Axis( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, forcelimit, torquelimit, friction, nocollide )
			if (constraint) then
				self:SendMessage( "Prop Axised." )
				undo.Create("Precision Axis")
				undo.AddEntity( constraint )
				undo.SetPlayer( self:GetOwner() )
				undo.Finish()
				self:GetOwner():AddCleanup( "constraints", constraint )
			end
		elseif ( mode == 4 ) then //ballsocket or advballsocket
			if ( self:GetClientNumber( "advballsocket", 0 ) == 1 ) then
				local constraint = constraint.AdvBallsocket( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, forcelimit, torquelimit, self:GetClientNumber( "XRotMin", -180 ), self:GetClientNumber( "YRotMin", -180 ), self:GetClientNumber( "ZRotMin", -180 ), self:GetClientNumber( "XRotMax", 180 ), self:GetClientNumber( "YRotMax", 180 ), self:GetClientNumber( "ZRotMax", 180 ), self:GetClientNumber( "XRotFric", 0 ), self:GetClientNumber( "YRotFric", 0 ), self:GetClientNumber( "ZRotFric", 0 ), self:GetClientNumber( "FreeMov", 0 ), nocollide )
				if (constraint) then
					self:SendMessage( "Prop Adv Ballsocketed." )
					undo.Create("Precision Advanced Ballsocket")
					undo.AddEntity( constraint )
					undo.SetPlayer( self:GetOwner() )
					undo.Finish()
					self:GetOwner():AddCleanup( "constraints", constraint )
				end
			else
				local constraint = constraint.Ballsocket( Ent1, Ent2, Bone1, Bone2, LPos2, forcelimit, torquelimit, nocollide )
				if (constraint) then
					self:SendMessage( "Prop Ballsocketed." )
					undo.Create("Precision Ballsocket")
					undo.AddEntity( constraint )
					undo.SetPlayer( self:GetOwner() )
					undo.Finish()
					self:GetOwner():AddCleanup( "constraints", constraint )
				end
			end
		elseif ( mode == 5 ) then //slider
			local constraint = constraint.Slider( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, width )
			if (constraint) then
				self:SendMessage( "Prop Slidered." )
				undo.Create("Precision Slider")
				undo.AddEntity( constraint )
				undo.SetPlayer( self:GetOwner() )
				undo.Finish()
				self:GetOwner():AddCleanup( "constraints", constraint )
			end
		end
		if (  util.tobool( nocollide ) && iNum != 0) then // not weld/axis/ballsocket or single application
			self:SendMessage( "Current settings applied." )
			local constraint = constraint.NoCollide(Ent1, Ent2, Bone1, Bone2)
		end
		if ( !Ent1:GetParent():IsValid() ) then
			Phys1:EnableCollisions( !nocollideall )
			if physdis then
				self:SendMessage( "Prop Physics Disabled." )
				local disablephysgun = false
				if ( self:GetClientNumber( "allowphysgun" ) == 0 ) then disablephysgun = true end
				Ent1:SetMoveType(MOVETYPE_NONE)
				Ent1.PhysgunDisabled = disablephysgun
				Ent1:SetUnFreezable( disablephysgun )
				if ( Ent1:GetMoveType() == 0 ) then
					Ent1:SetPos( Phys1:GetPos() )
					Ent1:SetAngles( Phys1:GetAngles() )
				end
			else
				Ent1:SetMoveType(MOVETYPE_VPHYSICS)
				Ent1.PhysgunDisabled = false
				Ent1:SetUnFreezable( false )
			end
		end
		Phys1:EnableMotion( !freeze )
		Ent1:DrawShadow( !util.tobool( self:GetClientNumber( "ShadowDisable", 0 ) ) )
		if ( mode == 6 ) then //parent
			self:DoParent( Ent1, Ent2 )
		end
	end
	// Clear the objects so we're ready to go again
	if ( inuse == self:GetOwner():GetName() ) then
		inuse = nil
	end
	self:ClearObjects()
end

function TOOL:DoNoConstraint( trace )
	if ( CLIENT ) then
		self:ClearObjects()
		return true
	end

	// Get client's CVars
	local freeze		= util.tobool( self:GetClientNumber( "freeze", 1 ) )
	local nocollideall	= util.tobool( self:GetClientNumber( "nocollideall", 0 ) )
	local physdis		= util.tobool( self:GetClientNumber( "physdisable", 0 ) )
	local autorotate	= util.tobool( self:GetClientNumber( "autorotate", 0 ) )
	local shadowdisable	= util.tobool( self:GetClientNumber( "ShadowDisable", 0 ) )
	local disablephysgun	= !util.tobool( self:GetClientNumber( "allowphysgun", 0 ) )

	// Get information we're about to use
	local Ent1 = trace.Entity
	local Phys1 = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )

	// Something happened, the entity became invalid half way through
	// Finish it.
	if ( !Ent1:IsValid() ) then
		self:ClearObjects()
		return false
	end
	if ( self:GetClientNumber( "massmode" ) == 1 ) then
		local NumApp = 0
		local TargetEnts = {}
		local EntsTab = {}
		local ConstsTab = {}
		GetAllEnts(Ent1, TargetEnts, EntsTab, ConstsTab)

		local angle = Vector(0,0,1)
		local anglechange = Vector(0,0,1)
		
		if ( autorotate ) then
			angle = Phys1:RotateAroundAxis( Vector( 0, 0, 1 ), 0 )
			anglechange = Vector( angle.p - (math.Round(angle.p/45))*45, angle.r - (math.Round(angle.r/45))*45, angle.y - (math.Round(angle.y/45))*45 )
			angle.p = (math.Round(angle.p/45))*45
			angle.r = (math.Round(angle.r/45))*45
			angle.y = (math.Round(angle.y/45))*45
			Phys1:SetAngle( angle )
			Phys1:Wake()
		end

		for key,CurrentEnt in pairs(TargetEnts) do
			if ( CurrentEnt and CurrentEnt:IsValid() ) then
				local CurrentPhys = CurrentEnt:GetPhysicsObject()
				if ( CurrentPhys:IsValid() ) then
					if autorotate then
						if !( CurrentEnt == Ent1 ) then
							local distance = math.sqrt(math.pow((CurrentEnt:GetPos().X-Ent1:GetPos().X),2)+math.pow((CurrentEnt:GetPos().Y-Ent1:GetPos().Y),2))
							local theta = math.atan((CurrentEnt:GetPos().Y-Ent1:GetPos().Y) / (CurrentEnt:GetPos().X-Ent1:GetPos().X)) - math.rad(anglechange.Z)
							if (CurrentEnt:GetPos().X-Ent1:GetPos().X) < 0 then
								CurrentEnt:SetPos( Vector( Ent1:GetPos().X - (distance*(math.cos(theta))), Ent1:GetPos().Y - (distance*(math.sin(theta))), CurrentEnt:GetPos().Z ) )
							else
								CurrentEnt:SetPos( Vector( Ent1:GetPos().X + (distance*(math.cos(theta))), Ent1:GetPos().Y + (distance*(math.sin(theta))), CurrentEnt:GetPos().Z ) )
							end
							CurrentPhys:SetAngle( CurrentPhys:RotateAroundAxis( Vector( 0, 0, -1 ), anglechange.Z ) )
							CurrentPhys:Wake()
						end
					end
					if ( !CurrentEnt:GetParent():IsValid() ) then
						CurrentPhys:EnableCollisions( !nocollideall )
						CurrentPhys:EnableMotion( !freeze )
					end
				end
				if ( !CurrentEnt:GetParent():IsValid() ) then
					if physdis then
						CurrentEnt:SetMoveType(MOVETYPE_NONE)
						CurrentEnt.PhysgunDisabled = disablephysgun
						CurrentEnt:SetUnFreezable( disablephysgun )
					else
						CurrentEnt:SetMoveType(MOVETYPE_VPHYSICS)
						CurrentEnt.PhysgunDisabled = false
						CurrentEnt:SetUnFreezable( false )
					end
				end
				CurrentEnt:DrawShadow( !shadowdisable )
			end
			NumApp = NumApp + 1
		end
		self:SendMessage( NumApp .. " props targeted :" )
	else
		if autorotate then
			local angle = Phys1:RotateAroundAxis( Vector( 0, 0, 1 ), 0 )
			angle.p = (math.Round(angle.p/45))*45
			angle.r = (math.Round(angle.r/45))*45
			angle.y = (math.Round(angle.y/45))*45
			Phys1:SetAngle( angle )
			Phys1:Wake()
		end
		Phys1:EnableCollisions( !nocollideall )
		if ( !Ent1:GetParent():IsValid() ) then
			if physdis then
				Ent1:SetMoveType(MOVETYPE_NONE)
				Ent1.PhysgunDisabled = disablephysgun
				Ent1:SetUnFreezable( disablephysgun )
			else
				Ent1:SetMoveType(MOVETYPE_VPHYSICS)
				Ent1.PhysgunDisabled = false
				Ent1:SetUnFreezable( false )
			end
			Phys1:EnableMotion( !freeze )
		end
		Ent1:DrawShadow( !shadowdisable )
	end

	// Clear the objects so we're ready to go again, though shouldn't be any here
	if ( inuse == self:GetOwner():GetName() ) then
		inuse = nil
	end
	self:ClearObjects()
end

function TOOL:SendMessage( message )
	if ( self:GetClientNumber( "enablefeedback" ) == 0 ) then return end
	if ( self:GetClientNumber( "chatfeedback" ) == 1 ) then
		self:GetOwner():PrintMessage( HUD_PRINTTALK, "Tool: " .. message )
	else
		self:GetOwner():PrintMessage( HUD_PRINTCENTER, message )
	end
end

function TOOL:LeftClick( trace )

	if ( iNum == 0 ) then
		trace.Entity:SetMoveType(MOVETYPE_VPHYSICS)
	end
	local iNum = self:NumObjects()
	local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )

	if ( iNum < 2 ) then
		// If there's no physics object then we can't constraint it!
		if (  SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone )  && ( !trace.Entity:GetParent():IsValid() || ! self:GetClientNumber( "removal" ) == 1 || !self:GetClientNumber( "mode" ) == 6) ) then
			if  !( (self:GetClientNumber( "mode" ) == 1 && iNum == 0) /*|| (self:GetClientNumber( "move" ) == 0 && self:GetClientNumber( "rotate" ) == 1 && iNum == 1) */) then
				return false
			end
		end

		// Don't weld players, or to players
		if ( trace.Entity:IsPlayer() ) then return false end

		// Don't do anything with stuff without any physics..
		if ( SERVER && !Phys:IsValid() && ( !trace.Entity:GetParent():IsValid() || !self:GetClientNumber( "removal" ) == 1 || !self:GetClientNumber( "mode" ) == 6 ) ) then
			if  !( self:GetClientNumber( "mode" ) == 1 && iNum == 0 ) then
				return false
			end
		end
	end

	if (iNum == 0) then
	
		if ( !trace.Entity:IsValid() ) then return false end
		if ( trace.Entity:GetClass() == "prop_vehicle_jeep" ) then return false end
		if ( self:GetClientNumber( "removal" ) == 1 ) then
			if ( CLIENT ) then return true end
			local StartEnt = trace.Entity
			local  bool = false
			local mode = self:GetClientNumber( "mode" )
			if ( self:GetClientNumber( "massmode" ) == 1 ) then
				local NumRem = 0
				local TargetEnts = {}
				local EntsTab = {}
				local ConstsTab = {}
				GetAllEnts(StartEnt, TargetEnts, EntsTab, ConstsTab)
				for key,CurrentEnt in pairs(TargetEnts) do
					if ( CurrentEnt and CurrentEnt:IsValid() ) then
						if ( mode == 1 ) then
							bool = constraint.RemoveConstraints( CurrentEnt, "NoCollide" )
							Phys:EnableCollisions(true)
						elseif ( mode == 2 ) then
							bool = constraint.RemoveConstraints( CurrentEnt, "Axis" )
						elseif ( mode == 3 ) then
							bool = constraint.RemoveConstraints( CurrentEnt, "Weld" )
						elseif ( mode == 4 ) then
							if ( self:GetClientNumber( "advballsocket", 0 ) == 1 ) then
								bool = constraint.RemoveConstraints( CurrentEnt, "AdvBallsocket" )
							else
								bool = constraint.RemoveConstraints( CurrentEnt, "Ballsocket" )
							end
						elseif ( mode == 5 ) then
							bool = constraint.RemoveConstraints( CurrentEnt, "Slider" )
						elseif ( mode == 6 ) then
							bool = CurrentEnt:GetParent():IsValid()
							if ( bool ) then
								self:UndoParent( CurrentEnt )
							end
						end
					end
					if ( bool ) then NumRem = NumRem + 1 end
				end
				self:SendMessage( NumRem .. " constraints removed." )
			else
				if ( mode == 1 ) then
					bool = constraint.RemoveConstraints( StartEnt, "NoCollide" )
					Phys:EnableCollisions(true)
				elseif ( mode == 2 ) then
					bool = constraint.RemoveConstraints( StartEnt, "Axis" )
				elseif ( mode == 3 ) then
					bool = constraint.RemoveConstraints( StartEnt, "Weld" )
				elseif ( mode == 4 ) then
					if ( self:GetClientNumber( "advballsocket", 0 ) == 1 ) then
						bool = constraint.RemoveConstraints( StartEnt, "AdvBallsocket" )
					else
						bool = constraint.RemoveConstraints( StartEnt, "Ballsocket" )
					end
				elseif ( mode == 5 ) then
					bool = constraint.RemoveConstraints( StartEnt, "Slider" )
				elseif ( mode == 6 ) then
					bool = StartEnt:GetParent():IsValid()
					if ( bool ) then
						self:UndoParent( StartEnt )
					end
				end
				if bool then
					self:SendMessage( "Constraint removed." )
				else
					self:SendMessage( "No constraint to remove." )
				end
			end
			return bool
		elseif self:GetClientNumber( "Move" ) == 0 then 
			if self:GetClientNumber( "rotate" ) == 1 then
				if ( CLIENT ) then return true end

				local oldposu = trace.Entity:GetPos()
				local oldangles = trace.Entity:GetAngles()

				local function MoveUndo( Undo, Entity, oldposu, oldangles )
					if Entity:IsValid() then
						Entity:SetAngles( oldangles )
						Entity:SetPos( oldposu )
					end
				end

				undo.Create("precision_rotate")
					undo.SetPlayer(self:GetOwner())
					undo.AddFunction( MoveUndo, trace.Entity, oldposu, oldangles )
				undo.Finish()

				Phys:EnableMotion( false ) //else it drifts
				local rotation = self:GetClientNumber( "rotation" )
				if ( inuse == nil || inuse == self:GetOwner():GetName() ) then
					inuse = self:GetOwner():GetName()
					axis = trace.HitNormal
					axisY = axis:Cross(trace.Entity:GetUp())
					if self:WithinABit( axisY, Vector(0,0,0) ) then
						axisY = axis:Cross(trace.Entity:GetForward())
					end
					axisZ = axisY:Cross(axis)
					realdegrees = 0
					lastdegrees = -((rotation/2) % rotation)
					realdegreesY = 0
					lastdegreesY = -((rotation/2) % rotation)
					realdegreesZ = 0
					lastdegreesZ = -((rotation/2) % rotation)
					OldPos = trace.HitPos
				else
					//inuse2 = self:GetOwner():GetName()
					axis2 = trace.HitNormal
					axis2Y = axis2:Cross(trace.Entity:GetUp())
					if self:WithinABit( axis2Y, Vector(0,0,0) ) then
						axis2Y = axis2:Cross(trace.Entity:GetForward())
					end
					axis2Z = trace.Entity:GetUp()//axis2Y:Cross(axis2)
					realdegrees2 = 0
					lastdegrees2 = -((rotation/2) % rotation)
					realdegrees2Y = 0
					lastdegrees2Y = -((rotation/2) % rotation)
					realdegrees2Z = 0
					lastdegrees2Z = -((rotation/2) % rotation)
					OldPos2 = trace.HitPos
				end
				self:SetObject( iNum + 2, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )
			elseif ( self:GetClientNumber( "mode" ) == 1 ) then
				if ( CLIENT ) then self:SendMessage( "Current settings applied." ) end
				self:DoNoConstraint( trace ) //both 0 and not needing a second object to constrain.. apply right away
				return true
			end
		end
	end

	self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal )

	if ( iNum > 1 ) then
		self:DoConstraint()
	elseif ( iNum == 1 ) then
		local offset		= self:GetClientNumber( "offset" )
		local move		= self:GetClientNumber( "move" )
		if ( move == 1 ) then
			if ( CLIENT ) then
				self:ReleaseGhostEntity()
				return true
			end

			// Get information we're about to use
			local Norm1, Norm2 = self:GetNormal(1),   self:GetNormal(2)
			local Phys1, Phys2 = self:GetPhys(1),     self:GetPhys(2)
			
			local Ang1, Ang2 = Norm1:Angle(), (Norm2 * -1):Angle()
			if self:GetClientNumber( "autorotate" ) == 1 then
				Ang2.p = (math.Round(Ang2.p/45))*45
				Ang2.r = (math.Round(Ang2.r/45))*45
				Ang2.y = (math.Round(Ang2.y/45))*45
				Norm2 = Ang2:Forward() * -1
			end
			local TargetAngle = Phys1:AlignAngles( Ang1, Ang2 )

			local rotation = self:GetClientNumber( "rotation" )
			if ( self:GetClientNumber( "rotate" ) == 1 ) then
				if ( inuse == nil || inuse == self:GetOwner():GetName() ) then
					inuse = self:GetOwner():GetName()
					axis = Norm2
					axisY = axis:Cross(self:GetEnt(1):GetUp())
					if self:WithinABit( axisY, Vector(0,0,0) ) then
						axisY = axis:Cross(self:GetEnt(1):GetForward())
					end
					axisZ = axisY:Cross(axis)
					realdegrees = 0
					lastdegrees = -((rotation/2) % rotation)
					realdegreesY = 0
					lastdegreesY = -((rotation/2) % rotation)
					realdegreesZ = 0
					lastdegreesZ = -((rotation/2) % rotation)
				else
					//inuse2 = self:GetOwner():GetName()
					axis2 = Norm2
					axis2Y = axis2:Cross(self:GetEnt(1):GetUp())
					if self:WithinABit( axis2Y, Vector(0,0,0) ) then
						axis2Y = axis2:Cross(self:GetEnt(1):GetForward())
					end
					axis2Z = self:GetEnt(1):GetUp()//axisY:Cross(axis)
					realdegrees2 = 0
					lastdegrees2 = -((rotation/2) % rotation)
					realdegrees2Y = 0
					lastdegrees2Y = -((rotation/2) % rotation)
					realdegrees2Z = 0
					lastdegrees2Z = -((rotation/2) % rotation)
				end
			else
				if ( inuse == nil || inuse == self:GetOwner():GetName() ) then
					axis = Norm2
					axisY = axis:Cross(self:GetEnt(1):GetUp())
					if self:WithinABit( axisY, Vector(0,0,0) ) then
						axisY = axis:Cross(self:GetEnt(1):GetForward())
					end
					axisZ = axisY:Cross(axis)
				else
					axis2 = Norm2
					axis2Y = axis:Cross(self:GetEnt(1):GetUp())
					if self:WithinABit( axis2Y, Vector(0,0,0) ) then
						axis2Y = axis2:Cross(self:GetEnt(1):GetForward())
					end
					axis2Z = axisY:Cross(axis)
				end
			end

			local oldposu = self:GetEnt(1):GetPos()
			local oldangles = self:GetEnt(1):GetAngles()

			local function MoveUndo( Undo, Entity, oldposu, oldangles )
				if Entity:IsValid() then
					Entity:SetAngles( oldangles )
					Entity:SetPos( oldposu )
				end
			end

			undo.Create("precision_move")
				undo.SetPlayer(self:GetOwner())
				undo.AddFunction( MoveUndo, self:GetEnt(1), oldposu, oldangles )
			undo.Finish()

			if self:GetClientNumber( "autorotate" ) == 1 then
				TargetAngle.p = (math.Round(TargetAngle.p/45))*45
				TargetAngle.r = (math.Round(TargetAngle.r/45))*45
				TargetAngle.y = (math.Round(TargetAngle.y/45))*45
			end

			Phys1:SetAngle( TargetAngle )

			local ang1 = 0
			local ang2 = 0
			local angle = 0

			if ( inuse == self:GetOwner():GetName() || inuse == nil ) then
				ang1 = Phys1:RotateAroundAxis( axis , 0 )//Phys1:GetAngles()
				ang1.p = ang1.p * axis.x
				ang1.r = ang1.r * axis.y
				ang1.y = ang1.y * axis.z
				ang2 = Phys2:RotateAroundAxis( axis , 0 )//Phys2:GetAngles()
				ang2.p = ang2.p * (-axis.x)
				ang2.r = ang2.r * (-axis.y)
				ang2.y = ang2.y * (-axis.z)

				ang1.p = ang2.p - ang1.p
				ang1.y = ang2.y - ang1.y
				ang1.r = ang2.r - ang1.r

				angle = Phys1:RotateAroundAxis( axis , ang2 )
			else
				ang1 = Phys1:RotateAroundAxis( axis2 , 0 )//Phys1:GetAngles()
				ang1.p = ang1.p * axis2.x
				ang1.r = ang1.r * axis2.y
				ang1.y = ang1.y * axis2.z
				ang2 = Phys2:RotateAroundAxis( axis2 , 0 )//Phys2:GetAngles()
				ang2.p = ang2.p * (-axis2.x)
				ang2.r = ang2.r * (-axis2.y)
				ang2.y = ang2.y * (-axis2.z)

				ang1.p = ang2.p - ang1.p
				ang1.y = ang2.y - ang1.y
				ang1.r = ang2.r - ang1.r

				angle = Phys1:RotateAroundAxis( axis2 , ang2 )
			end
			Phys1:SetAngle( angle )

			local NewOffset = offset
			local offsetpercent		= self:GetClientNumber( "offsetpercent" ) == 1
			if ( offsetpercent ) then
				local  Ent2  = self:GetEnt(2)
				local glower = Ent2:OBBMins()
				local gupper = Ent2:OBBMaxs()
				local height = math.abs(gupper.z - glower.z) -0.5
				if self:WithinABit(Norm2,Ent2:GetForward()) then
					height = math.abs(gupper.x - glower.x)-0.5
				elseif self:WithinABit(Norm2,Ent2:GetRight()) then
					height = math.abs(gupper.y - glower.y)-0.5
				end
				NewOffset = NewOffset / 100
				NewOffset = NewOffset * height
			end
			Norm2 = Norm2 * (-0.0625 + NewOffset)
			local TargetPos = self:GetPos(2) + (Phys1:GetPos() - self:GetPos(1)) + (Norm2)

			// Set the position

			Phys1:SetPos( TargetPos )
			Phys1:EnableMotion( false )

			// Wake up the physics object so that the entity updates
			Phys1:Wake()
		end //end move check

		self:ReleaseGhostEntity()
		local rotate		= self:GetClientNumber( "rotate" ) == 1
		if ( rotate ) then
			self:SetStage( iNum+1 )
			if ( inuse == nil || inuse == self:GetOwner():GetName() ) then
				inuse = self:GetOwner():GetName()
			end
		else
			self:DoConstraint()
		end
	else
		local move		= self:GetClientNumber( "move" )
		if ( move ) then
			self:StartGhostEntity( trace.Entity )
		end
		self:SetStage( iNum+1 )
	end
	return true
end

function TOOL:WithinABit( v1, v2 )
	local tol = 0.1
	local da = v1.x-v2.x
	local db = v1.y-v2.y
	local dc = v1.z-v2.z
	if da < tol && da > -tol && db < tol && db > -tol && dc < tol && dc > -tol then
		return true
	else
		da = v1.x+v2.x
		db = v1.y+v2.y
		dc = v1.z+v2.z
		if da < tol && da > -tol && db < tol && db > -tol && dc < tol && dc > -tol then
			return true
		else
			return false
		end
	end
end

if ( SERVER ) then
	function GetAllEnts( Ent, OrderedEntList, EntsTab, ConstsTab )
		if ( Ent and Ent:IsValid() ) and ( !EntsTab[ Ent:EntIndex() ] ) then
			EntsTab[ Ent:EntIndex() ] = Ent
			table.insert(OrderedEntList, Ent)
			if ( !constraint.HasConstraints( Ent ) ) then return OrderedEntList end
			for key, ConstraintEntity in pairs( Ent.Constraints ) do
				if ( !ConstsTab[ ConstraintEntity ] ) then
					ConstsTab[ ConstraintEntity ] = true
					local ConstTable = ConstraintEntity:GetTable()
					for i=1, 6 do
						local e = ConstTable[ "Ent"..i ]
						if ( e and e:IsValid() ) and ( !EntsTab[ e:EntIndex() ] ) then
							GetAllEnts( e, OrderedEntList, EntsTab, ConstsTab )
						end
					end
				end
			end
		end
		return OrderedEntList
	end
end

function TOOL:UpdateCustomGhost( ghost, player, offset )
	// Ghost is identically buggy to that of easyweld...  welding two frozen props and two unfrozen props yields different ghosts even if identical allignment
	if (ghost == nil) then return end
	if (!ghost:IsValid()) then ghost = nil return end

	local tr = utilx.GetPlayerTrace( player, player:GetCursorAimVector() )
	local trace = util.TraceLine( tr )
	if (!trace.Hit) then return end

	local Ang1, Ang2 = self:GetNormal(1):Angle(), (trace.HitNormal * -1):Angle()
	local TargetAngle = self:GetEnt(1):AlignAngles( Ang1, Ang2 )

	self.GhostEntity:SetPos( self:GetEnt(1):GetPos() )
	
	if self:GetClientNumber( "autorotate" ) == 1 then
		TargetAngle.p = (math.Round(TargetAngle.p/45))*45
		TargetAngle.r = (math.Round(TargetAngle.r/45))*45
		TargetAngle.y = (math.Round(TargetAngle.y/45))*45
	end
	self.GhostEntity:SetAngles( TargetAngle )

	local TraceNormal = trace.HitNormal

	local offsetpercent		= self:GetClientNumber( "offsetpercent" ) == 1
	local NewOffset = offset
	if ( offsetpercent ) then
		local glower = trace.Entity:OBBMins()
		local gupper = trace.Entity:OBBMaxs()
		local height = math.abs(gupper.z - glower.z) -0.5
		if self:WithinABit(TraceNormal,trace.Entity:GetForward()) then
			height = math.abs(gupper.x - glower.x) -0.5
		elseif self:WithinABit(TraceNormal,trace.Entity:GetRight()) then
			height = math.abs(gupper.y - glower.y) -0.5
		end
		NewOffset = NewOffset / 100
		NewOffset = NewOffset * height
	end

	local TranslatedPos = ghost:LocalToWorld( self:GetLocalPos(1) )
	local TargetPos = trace.HitPos + (self:GetEnt(1):GetPos() - TranslatedPos) + (TraceNormal*NewOffset)

	self.GhostEntity:SetPos( TargetPos )
end

function TOOL:Think()
	if (self:NumObjects() < 1) then return end
	local Ent1 = self:GetEnt(1)
	if ( SERVER ) then
		if ( !Ent1:IsValid() ) then
			self:ClearObjects()
			return
		end
	end

	if (self:NumObjects() == 1 && !((self:GetClientNumber( "move" ) == 0) && (self:GetClientNumber( "rotate" ) == 1) )) then
		if ( self:GetClientNumber( "move" ) == 1 ) then
			local offset		= self:GetClientNumber( "offset" )
			self:UpdateCustomGhost( self.GhostEntity, self:GetOwner(), offset )
		end
	else
		local rotate		= self:GetClientNumber( "rotate" ) == 1
		if ( SERVER && rotate ) then
			local offset		= self:GetClientNumber( "offset" )

			local Phys1 = self:GetPhys(1)

			local cmd = self:GetOwner():GetCurrentCommand()

			local rotation		= self:GetClientNumber( "rotation" )
			if ( rotation < 0.02 ) then rotation = 0.02 end
			local degrees = cmd:GetMouseX() * 0.02

			local newdegrees = 0
			local changedegrees = 0

			local angle = 0
			if( self:GetOwner():KeyDown( IN_RELOAD ) ) then
				if ( inuse == self:GetOwner():GetName() ) then
					realdegreesY = realdegreesY + degrees
					newdegrees =  realdegreesY - ((realdegreesY + (rotation/2)) % rotation)
					changedegrees = lastdegreesY - newdegrees
					lastdegreesY = newdegrees
					angle = Phys1:RotateAroundAxis( axisY , changedegrees )
					Phys1:SetAngle( angle )
				else
					realdegrees2Y = realdegrees2Y + degrees
					newdegrees =  realdegrees2Y - ((realdegrees2Y + (rotation/2)) % rotation)
					changedegrees = lastdegrees2Y - newdegrees
					lastdegrees2Y = newdegrees
					angle = Phys1:RotateAroundAxis( axisY , changedegrees )
					Phys1:SetAngle( angle )
				end
			elseif( self:GetOwner():KeyDown( IN_ATTACK2 ) ) then
				if ( inuse == self:GetOwner():GetName() ) then
					realdegreesZ = realdegreesZ + degrees
					newdegrees =  realdegreesZ - ((realdegreesZ + (rotation/2)) % rotation)
					changedegrees = lastdegreesZ - newdegrees
					lastdegreesZ = newdegrees
					angle = Phys1:RotateAroundAxis( axisZ , changedegrees )
					Phys1:SetAngle( angle )
				else
					realdegrees2Z = realdegrees2Z + degrees
					newdegrees =  realdegrees2Z - ((realdegrees2Z + (rotation/2)) % rotation)
					changedegrees = lastdegrees2Z - newdegrees
					lastdegrees2Z = newdegrees
					angle = Phys1:RotateAroundAxis( axisZ , changedegrees )
					Phys1:SetAngle( angle )
				end
			else
				if ( inuse == self:GetOwner():GetName() ) then
					realdegrees = realdegrees + degrees
					newdegrees =  realdegrees - ((realdegrees + (rotation/2)) % rotation)
					changedegrees = lastdegrees - newdegrees
					lastdegrees = newdegrees
					angle = Phys1:RotateAroundAxis( axis , changedegrees )
				else
					realdegrees2 = realdegrees2 + degrees
					newdegrees =  realdegrees2 - ((realdegrees2 + (rotation/2)) % rotation)
					changedegrees = lastdegrees2 - newdegrees
					lastdegrees2 = newdegrees
					angle = Phys1:RotateAroundAxis( axis2 , changedegrees )
				end
				Phys1:SetAngle( angle )
			end

			if ( self:GetClientNumber( "move" ) == 1 ) then
				local WPos2 = self:GetPos(2)
				local Ent2 = self:GetEnt(2)
				// Move so spots join up
				local Norm2 = self:GetNormal(2)

				local NewOffset = offset
				local offsetpercent		= self:GetClientNumber( "offsetpercent" ) == 1
				if ( offsetpercent ) then
					local glower = Ent2:OBBMins()
					local gupper = Ent2:OBBMaxs()
					local height = math.abs(gupper.z - glower.z) -0.5
					if self:WithinABit(Norm2,Ent2:GetForward()) then
						height = math.abs(gupper.x - glower.x) -0.5
					elseif self:WithinABit(Norm2,Ent2:GetRight()) then
						height = math.abs(gupper.y - glower.y) -0.5
					end
					NewOffset = NewOffset / 100
					NewOffset = NewOffset * height
				end

				Norm2 = Norm2 * (-0.0625 + NewOffset)
				local TargetPos = WPos2 + (Phys1:GetPos() - self:GetPos(1)) + (Norm2)
				Phys1:SetPos( TargetPos )
			else
				// Move so rotating on axis

				local TargetPos = (Phys1:GetPos() - self:GetPos(1))
				if ( inuse == self:GetOwner():GetName() ) then
					TargetPos = TargetPos + OldPos
				else
					TargetPos = TargetPos + OldPos2
				end
				Phys1:SetPos( TargetPos )
			end
			Phys1:Wake()
		end
	end
end

function TOOL:Nudge( trace, direction )
	if (!trace.Entity:IsValid() || trace.Entity:IsPlayer() ) then return false end
	local Phys1 = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
	local offset		= self:GetClientNumber( "nudge" )
	//if ( offset == 0 ) then offset = 1 end
	local NewOffset = offset
	local offsetpercent		= self:GetClientNumber( "nudgepercent" ) == 1
	if ( offsetpercent ) then
		local glower = trace.Entity:OBBMins()
		local gupper = trace.Entity:OBBMaxs()
		local height = math.abs(gupper.z - glower.z) -0.5
		if self:WithinABit(trace.HitNormal,trace.Entity:GetForward()) then
			height = math.abs(gupper.x - glower.x)-0.5
		elseif self:WithinABit(trace.HitNormal,trace.Entity:GetRight()) then
			height = math.abs(gupper.y - glower.y)-0.5
		end
		NewOffset = NewOffset / 100
		NewOffset = NewOffset * height
	end

	if ( self:GetClientNumber( "massmode" ) == 1 ) then
		local NumApp = 0
		local TargetEnts = {}
		local EntsTab = {}
		local ConstsTab = {}
		GetAllEnts(trace.Entity, TargetEnts, EntsTab, ConstsTab)
		for key,CurrentEnt in pairs(TargetEnts) do
			if ( CurrentEnt and CurrentEnt:IsValid() ) then
				local CurrentPhys = CurrentEnt:GetPhysicsObject()
				if ( CurrentPhys:IsValid() ) then

					/*if ( self:GetClientNumber( "nudgeundo" ) == 1 ) then
						local oldpos = CurrentPhys:GetPos()
						local function NudgeUndo( Undo, Entity, oldpos )
							if CurrentEnt:IsValid() then
								CurrentEnt:SetPos( oldpos )
							end
						end
						undo.Create("precision_nudge")
							undo.SetPlayer(self:GetOwner())
							undo.AddFunction( NudgeUndo, CurrentEnt, oldpos )
						undo.Finish()
					end*/// todo: all in 1 undo for mass nudging

					local TargetPos = CurrentPhys:GetPos() + trace.HitNormal * NewOffset * direction
					CurrentPhys:SetPos( TargetPos )
					CurrentPhys:Wake()
					if (CurrentEnt:GetMoveType() == 0 ) then //phys disabled, so move manually
						CurrentEnt:SetPos( TargetPos )
					end

				end
			end
			NumApp = NumApp + 1
		end
		if ( direction == -1 ) then
			self:SendMessage( NumApp .. " props pushed." )
		elseif ( direction == 1 ) then
			self:SendMessage( NumApp .. " props pulled." )
		else
			self:SendMessage( NumApp .. " props nudged." )
		end
	else
		if ( self:GetClientNumber( "nudgeundo" ) == 1 ) then
			local oldpos = Phys1:GetPos()
			local function NudgeUndo( Undo, Entity, oldpos )
				if trace.Entity:IsValid() then
					trace.Entity:SetPos( oldpos )
				end
			end
			undo.Create("precision_nudge")
				undo.SetPlayer(self:GetOwner())
				undo.AddFunction( NudgeUndo, trace.Entity, oldpos )
			undo.Finish()
		end
		local TargetPos = Phys1:GetPos() + trace.HitNormal * NewOffset * direction
		Phys1:SetPos( TargetPos )
		Phys1:Wake()
		if ( trace.Entity:GetMoveType() == 0 ) then
			trace.Entity:SetPos( TargetPos )
		end
		if ( direction == -1 ) then
			self:SendMessage( "prop pushed." )
		elseif ( direction == 1 ) then
			self:SendMessage( "prop pulled." )
		else
			self:SendMessage( "prop nudged." )
		end
	end
	return true
end

function TOOL:RightClick( trace )
	local rotate = self:GetClientNumber( "rotate" ) == 1
	local move = self:GetClientNumber( "move" ) == 1
	if ( (rotate && !move && self:NumObjects() == 1) || (rotate && self:NumObjects() == 2 ) ) then
		if ( CLIENT ) then return false end
	else
		if ( CLIENT ) then return true end
		return self:Nudge( trace, -1 )
	end
end

function TOOL:Reload( trace )
	local rotate = self:GetClientNumber( "rotate" ) == 1
	local move = self:GetClientNumber( "move" ) == 1
	if ( (rotate && !move && self:NumObjects() == 1) || (rotate && self:NumObjects() == 2 ) ) then
		if ( CLIENT ) then return false end
	else
		if ( CLIENT ) then return true end
		return self:Nudge( trace, 1 )
	end
end

if CLIENT then
	function TOOL:Deploy()
		precision_updatecpanel()
	end
	local showadvmenu = 0
	local showspecificmenu = 0
	local showadvballmenu = 0
	local expandpresets = 0

	local function AddDefControls( Panel )
		Panel:ClearControls()

		if ( expandpresets == 1 ) then
			Panel:AddControl( "Button", { Label = "#/\\ Show Custom Preset List /\\", Command = "easy_precision_presetmenu", Description = "Contracts Presets menu"  } )
			Panel:AddControl("ListBox",
			{
				Label = "#Presets (Tool mode doesnt refresh)",
				MenuButton = 1,
				Folder = "easyprecision",
				Height = 124,
				Options = 
				{
					["#Default Move (with rotate 15)"] =
					{
						easy_precision_offset = 0,
						easy_precision_offsetpercent = 1,
						easy_precision_nudge = 25,
						easy_precision_nudgepercent = 1,
						easy_precision_freeze = 1,
						easy_precision_nocollideall = 0,
						easy_precision_rotation = 15,
						easy_precision_rotate = 1,
						easy_precision_mode = 1,
						easy_precision_removal = 0,
						easy_precision_move = 1,
						easy_precision_physdisable = 0,
						easy_precision_autorotate = 1,
						easy_precision_massmode = 0,
						easy_precision_autorotate = 0
					},
					["#Easyweld Clone (just to compare)"] =
					{
						easy_precision_offset = 1.0625,
						easy_precision_nudge = 0,
						easy_precision_freeze = 0,
						easy_precision_nocollideall = 0,
						easy_precision_rotation = 0.02,
						easy_precision_rotate = 1,
						easy_precision_mode = 3,
						easy_precision_offsetpercent = 0,
						easy_precision_ShadowDisable = 0,
						easy_precision_removal = 0,
						easy_precision_move = 1,
						easy_precision_physdisable = 0,
						easy_precision_autorotate = 0,
						easy_precision_massmode = 0,
						easy_precision_autorotate = 0
					},
					["#Parent Mode"] =
					{
						easy_precision_freeze = 1,
						easy_precision_nocollideall = 0,
						easy_precision_rotate = 0,
						easy_precision_nudge = 25,
						easy_precision_nudgepercent = 1,
						easy_precision_mode = 6,
						easy_precision_removal = 0,
						easy_precision_move = 0,
						easy_precision_physdisable = 0,
						easy_precision_allowphysgun = 0,
						easy_precision_massmode = 0,
						easy_precision_autorotate = 0
					},
					["#Mass Rotation to World"] =
					{
						easy_precision_freeze = 1,
						easy_precision_nudge = 25,
						easy_precision_nudgepercent = 1,
						easy_precision_nocollideall = 0,
						easy_precision_rotate = 0,
						easy_precision_mode = 1,
						easy_precision_removal = 0,
						easy_precision_move = 0,
						easy_precision_physdisable = 0,
						easy_precision_massmode = 1,
						easy_precision_autorotate = 1
					},
					["#Mass Disable Physics, Shadow"] =
					{
						easy_precision_freeze = 1,
						easy_precision_nocollideall = 0,
						easy_precision_rotate = 0,
						easy_precision_nudge = 25,
						easy_precision_nudgepercent = 1,
						easy_precision_mode = 1,
						easy_precision_removal = 0,
						easy_precision_move = 0,
						easy_precision_physdisable = 1,
						easy_precision_ShadowDisable = 1,
						easy_precision_allowphysgun = 0,
						easy_precision_massmode = 1,
						easy_precision_autorotate = 0
					},
					["#Ballsocket Snap"] =
					{
						easy_precision_offset = 0,
						easy_precision_nudge = 25,
						easy_precision_nudgepercent = 1,
						easy_precision_freeze = 1,
						easy_precision_nocollideall = 0,
						easy_precision_rotation = 15,
						easy_precision_rotate = 0,
						easy_precision_mode = 4,
						easy_precision_offsetpercent = 1,
						easy_precision_removal = 0,
						easy_precision_move = 1,
						easy_precision_physdisable = 0,
						easy_precision_advballsocket = 0,
						easy_precision_massmode = 0,
						easy_precision_autorotate = 0
					}
				}
			})
			
		else
			Panel:AddControl( "Button", { Label = "#\\/ Show Default Presets \\/", Command = "easy_precision_presetmenu", Description = "Expands Presets menu"  } )
			Panel:AddControl("ComboBox",
			{
				Label = "#Presets",
				MenuButton = 1,
				Folder = "easyprecision",
				Options = {},
				CVars =
				{
					[0] = "easy_precision_offset",
					[1] = "easy_precision_forcelimit",
					[2] = "easy_precision_freeze",
					[3] = "easy_precision_nocollide",
					[4] = "easy_precision_nocollideall",
					[5] = "easy_precision_rotation",
					[6] = "easy_precision_rotate",
					[7] = "easy_precision_torquelimit",
					[8] = "easy_precision_friction",
					[9] = "easy_precision_mode",
					[10] = "easy_precision_width",
					[11] = "easy_precision_offsetpercent",
					[12] = "easy_precision_removal",
					[13] = "easy_precision_move",
					[14] = "easy_precision_physdisable",
					[15] = "easy_precision_advballsocket",
					[16] = "easy_precision_XRotMin",
					[17] = "easy_precision_XRotMax",
					[18] = "easy_precision_YRotMin",
					[19] = "easy_precision_YRotMax",
					[20] = "easy_precision_ZRotMin",
					[21] = "easy_precision_ZRotMax",
					[22] = "easy_precision_XRotFric",
					[23] = "easy_precision_YRotFric",
					[24] = "easy_precision_ZRotFric",
					[25] = "easy_precision_FreeMov",
					[26] = "easy_precision_ShadowDisable",
					[27] = "easy_precision_allowphysgun",
					[28] = "easy_precision_autorotate",
					[29] = "easy_precision_massmode",
					[30] = "easy_precision_nudge",
					[31] = "easy_precision_nudgepercent"
				}
			})
		end

		Panel:AddControl( "Slider",  { Label	= "Nudge Amount",
					Type	= "Float",
					Min		= 1,
					Max		= 100,
					Command = "easy_precision_nudge",
					Description = "Distance to push/pull props with altfire/reload"}	 )

		Panel:AddControl( "Checkbox", { Label = "Nudge as Percent (%) of prop width", Command = "easy_precision_nudgepercent", Description = "Unchecked = Exact units, Checked = takes % of width from target prop when pushing/pulling" } )


		local params = {Label = "Tool Mode",Description = "Selects Current Tool Mode", MenuButton = "0", Height = 118, Options = {}}
		params.Options["1    Move (no constraining, low lag)"] = {easy_precision_mode = "1"}
		params.Options["3    Axis"] = {easy_precision_mode = "2"} // swapped for menu order as weld
		params.Options["2    Weld"] = {easy_precision_mode = "3"} //  is far more common than axis
		params.Options["4    Ballsocket"] = {easy_precision_mode = "4"}
		params.Options["5    Slider (Spazzy on low weight props)"] = {easy_precision_mode = "5"}
		params.Options["6    Parent Link (duping causes issues)"] = {easy_precision_mode = "6"}

		Panel:AddControl( "ListBox", params )

		Panel:AddControl( "Header", { Text = "Additional Parameters", Description	= "These options are applied in addition to the currently selected mode" }  )

		Panel:AddControl( "Slider",  { Label	= "Offset (or inset if negative)",
					Type	= "Float",
					Min		= 0,
					Max		= 100,
					Command = "easy_precision_offset",
					Description = "Distance between joined props.  Type in negative to inset when moving."}	 )

		Panel:AddControl( "Checkbox", { Label = "Move Target?", Command = "easy_precision_move", Description = "Uncheck this if you don't want the props to move when constraining." } )

		Panel:AddControl( "Checkbox", { Label = "Offset as Percent (%) of prop width", Command = "easy_precision_offsetpercent", Description = "Unchecked = Exact units, Checked = takes % of width from second prop" } )

		Panel:AddControl( "Slider",  { Label	= "Rotation Snap Amount (Degrees)",
					Type	= "Float",
					Min		= 0.02,
					Max		= 90,
					Command = "easy_precision_rotation",
					Description = "Rotation rotates by this amount at a time. No more guesswork. Min: 0.02 degrees"}	 )

		Panel:AddControl( "Checkbox", { Label = "Rotate Target?", Command = "easy_precision_rotate", Description = "Uncheck this to remove the extra click for rotation. Handy for speed building." } )

		Panel:AddControl( "Checkbox", { Label = "Freeze Target", Command = "easy_precision_freeze", Description = "Freeze props when this tool is used" } )

		Panel:AddControl( "Checkbox", { Label = "No Collide Targets", Command = "easy_precision_nocollide", Description = "Nocollide pairs of props when this tool is used. Note: No current way to remove this constraint."  } )

		Panel:AddControl( "Checkbox", { Label = "Autorotate to World", Command = "easy_precision_autorotate", Description = "Rotates to the nearest world axis (similar to holding sprint and use with physgun)"  } )

		if ( showspecificmenu == 1 ) then
			Panel:AddControl( "Button", { Label = "/\\ Hide Mode Specific Options /\\", Command = "easy_precision_specificmenu", Description = "Contract menu - These apply to specific constraint modes"  } )

			Panel:AddControl( "Slider",  { Label	= "Constraint Force Breakpoint",
					Type	= "Float",
					Min		= 0.0,
					Max		= 50000,
					Command = "easy_precision_forcelimit",
					Description = "Applies to most constraint modes" }	 )

			Panel:AddControl( "Slider",  { Label	= "Axis Torque Breakpoint",
					Type	= "Float",
					Min		= 0.0,
					Max		= 50000,
					Command = "easy_precision_torquelimit",
					Description = "Breakpoint of turning/rotational force"}	 )

			Panel:AddControl( "Slider",  { Label	= "Axis Friction",
					Type	= "Float",
					Min		= 0.0,
					Max		= 100,
					Command = "easy_precision_friction",
					Description = "Turning resistance, this is best at 0 in most cases to conserve energy"}	 )

			Panel:AddControl( "Slider",  { Label	= "Slider Width",
					Type	= "Float",
					Min		= 0.0,
					Max		= 10,
					Command = "easy_precision_width",
					Description = "Width of the slider black line (0 = invisible)"}	 )
		else
			Panel:AddControl( "Button", { Label = "\\/ Show Mode Specific Options \\/", Command = "easy_precision_specificmenu", Description = "Expand menu - These apply to specific constraint modes"  } )
		end

		if ( showadvmenu == 1 ) then
			Panel:AddControl( "Button", { Label = "/\\ Hide Other Options /\\", Command = "easy_precision_advancedmenu", Description = "Contract menu - These are usually left off"  } )

			Panel:AddControl( "Checkbox", { Label = "Constraint Removal Mode", Command = "easy_precision_removal", Description = "When enabled, attempts to undo constraints of the current mode on targeted props (Much like the reload function of other tools).  Use 'move' mode to remove nocollideall constraint." } )
			Panel:AddControl( "Checkbox", { Label = "Advanced: Entire Contraption(!) Mode", Command = "easy_precision_massmode", Description = "For mass constraining or removal or nudging or applying of things. Yay generic."  } )
			Panel:AddControl( "Checkbox", { Label = "Disable Prop Shadow", Command = "easy_precision_ShadowDisable", Description = "Disables shadows cast from the prop"  } )
			Panel:AddControl( "Checkbox", { Label = "Advanced: Only Collide with Player", Command = "easy_precision_nocollideall", Description = "Nocollides the first prop to everything and the world (except players collide with it). Warning: don't let it fall away through the world."  } )
			Panel:AddControl( "Checkbox", { Label = "Advanced: Disable Physics on Prop", Command = "easy_precision_physdisable", Description = "Disables physics on the first prop (gravity, being shot etc won't effect it)"  } )
			Panel:AddControl( "Checkbox", { Label = "Adv: Allow Physgun on Parent/PhysDis Props", Command = "easy_precision_allowphysgun", Description = "Disabled to stop accidents, use this if you want to play with the parenting hierarchy"  } )
		else
			Panel:AddControl( "Button", { Label = "\\/ Show Other Options \\/", Command = "easy_precision_advancedmenu", Description = "Expand menu - These are usually left off"  } )
		end

		if ( showadvballmenu == 1 ) then
			Panel:AddControl( "Button", { Label = "/\\ Hide Advanced Ballsocket Options /\\", Command = "easy_precision_ballsocketmenu", Description = "Contract menu"  } )

			Panel:AddControl( "Checkbox", { Label = "Turn Ballsocket Mode Into Advanced?", Command = "easy_precision_advballsocket", Description = "Makes the 'ballsocket' constraint follow the rules set out below"  } )

			Panel:AddControl( "Slider",  { Label	= "X Rotation Minimum",
					Type	= "Float",
					Min		= -180,
					Max		= 180,
					Command = "easy_precision_XRotMin",
					Description = "Rotation minimum of advanced ballsocket in X axis"}	 )

			Panel:AddControl( "Slider",  { Label	= "X Rotation Maximum",
					Type	= "Float",
					Min		= -180,
					Max		= 180,
					Command = "easy_precision_XRotMax",
					Description = "Rotation maximum of advanced ballsocket in X axis"}	 )

			Panel:AddControl( "Slider",  { Label	= "Y Rotation Minimum",
					Type	= "Float",
					Min		= -180,
					Max		= 180,
					Command = "easy_precision_YRotMin",
					Description = "Rotation minimum of advanced ballsocket in Y axis"}	 )

			Panel:AddControl( "Slider",  { Label	= "Y Rotation Maximum",
					Type	= "Float",
					Min		= -180,
					Max		= 180,
					Command = "easy_precision_YRotMax",
					Description = "Rotation maximum of advanced ballsocket in Y axis"}	 )

			Panel:AddControl( "Slider",  { Label	= "Z Rotation Minimum",
					Type	= "Float",
					Min		= -180,
					Max		= 180,
					Command = "easy_precision_ZRotMin",
					Description = "Rotation minimum of advanced ballsocket in Z axis"}	 )

			Panel:AddControl( "Slider",  { Label	= "Z Rotation Maximum",
					Type	= "Float",
					Min		= -180,
					Max		= 180,
					Command = "easy_precision_ZRotMax",
					Description = "Rotation maximum of advanced ballsocket in Z axis"}	 )

			Panel:AddControl( "Slider",  { Label	= "X Rotation Friction",
					Type	= "Float",
					Min		= 0,
					Max		= 100,
					Command = "easy_precision_XRotFric",
					Description = "Rotation friction of advanced ballsocket in X axis"}	 )

			Panel:AddControl( "Slider",  { Label	= "Y Rotation Friction",
					Type	= "Float",
					Min		= 0,
					Max		= 100,
					Command = "easy_precision_YRotFric",
					Description = "Rotation friction of advanced ballsocket in Y axis"}	 )

			Panel:AddControl( "Slider",  { Label	= "Z Rotation Friction",
					Type	= "Float",
					Min		= 0,
					Max		= 100,
					Command = "easy_precision_ZRotFric",
					Description = "Rotation friction of advanced ballsocket in Z axis"}	 )


			Panel:AddControl( "Checkbox", { Label = "Free Movement", Command = "easy_precision_FreeMov", Description = "Only lock relative rotation, not position?"  } )
		else
			Panel:AddControl( "Button", { Label = "\\/ Show Advanced Ballsocket Options \\/", Command = "easy_precision_ballsocketmenu", Description = "Expand menu"  } )
		end

		Panel:AddControl( "Checkbox", { Label = "Enable tool feedback messages?", Command = "easy_precision_enablefeedback", Description = "Toggle for feedback messages incase they get annoying"  } )
		Panel:AddControl( "Checkbox", { Label = "On = Feedback in Chat, Off = Centr Scrn", Command = "easy_precision_chatfeedback", Description = "Chat too cluttered? Can have messages centre screen instead"  } )
		Panel:AddControl( "Checkbox", { Label = "Add Nudges to Undo List", Command = "easy_precision_nudgeundo", Description = "For if you're in danger of nudging somthing to where you can't reach it"  } )
	end

	local function precision_presets()
		if ( expandpresets == 0 ) then
			expandpresets = 1
		else
			expandpresets = 0
		end
		precision_updatecpanel()
	end
	concommand.Add( "easy_precision_presetmenu", precision_presets )

	local function precision_specificmenu()
		if ( showspecificmenu == 0 ) then
			showspecificmenu = 1
		else
			showspecificmenu = 0
		end
		precision_updatecpanel()
	end
	concommand.Add( "easy_precision_specificmenu", precision_specificmenu )

	local function precision_advmenu()
		if ( showadvmenu == 0 ) then
			showadvmenu = 1
		else
			showadvmenu = 0
		end
		precision_updatecpanel()
	end
	concommand.Add( "easy_precision_advancedmenu", precision_advmenu )


	local function precision_advballsocket()
		if ( showadvballmenu == 0 ) then
			showadvballmenu = 1
		else
			showadvballmenu = 0
		end
		precision_updatecpanel()
	end
	concommand.Add( "easy_precision_ballsocketmenu", precision_advballsocket )

	function TOOL.BuildCPanel( Panel )
		AddDefControls( Panel )
	end

	function precision_updatecpanel()
		local Panel = GetControlPanel( "easy_precision" )
		if (!Panel) then return end
		//custom panel building ( wtf does Panel:AddDefaultControls() get it's defaults from? )
		AddDefControls( Panel )
	end
	concommand.Add( "easy_precision_updatecpanel", precision_updatecpanel )

	language.Add( "Tool_easy_precision_name", "Easy Precision Tool 0.9a" )
	language.Add( "Tool_easy_precision_desc", "Accurately positions props" )
	language.Add( "Tool_easy_precision_0", "Target the prop you wish to move. Secondary fire and Reload push and pull props by Offset (1 if no offset)" )
	language.Add( "Tool_easy_precision_1", "Target the second prop. If enabled, this will move the first prop. Swap weps to cancel." )
	language.Add( "Tool_easy_precision_2", "Turn left and right to rotate the prop (unticking 'Rotate Target?' disables this stage)" )

	language.Add("Undone_easy_precision", "Undone Precision Constraint")
	language.Add("Undone_precision_nudge", "Undone Precision Nudge")
	language.Add("Undone_precision_rotate", "Undone Precision Rotate")
	language.Add("Undone_precision_move", "Undone Precision Move")

	function TOOL:FreezeMovement()
		local iNum = self:GetStage()
		if ( iNum > 1 ) then
			return true
		elseif ( iNum > 0 && self:GetClientNumber( "move" ) == 0 && self:GetClientNumber( "rotate" ) == 1 ) then
			return true
		end
		return false
	end
end

function TOOL:Holster()
	self:ClearObjects()
end